昨天從執行 Hello Docker 的過程中,了解 Docker 的三個基本元件。今天會更進一步地說明 docker run
更多細節。
首先,先回顧這張示意圖:
Hello Docker 使用的 docker run
指令,可以一條龍處理上圖所有任務。等等將會示範如何不使用 docker run
來達成執行 container,同時換用 BusyBox image 來做示範。
BusyBox 是一個 Linux 指令工具包,它執行後會進到 container 的命令提示字元裡,接著就能使用 BusyBox 所提供的 Linux 指令。
執行 container 任務先簡單拆解如下:
首先 Docker 會確認 image 是否存在,可以用 docker images
指令來查看本機的 image,接著使用 docker pull
指令下載 image:
# 查看本機 image
docker images busybox
# 下載 image
docker pull busybox
一開始執行 docker images busybox
會出現空列表,代表 host 沒有對應的 image,會需要下載。如果 image 存在,會跳到建立 container步驟。下載完成後,可以用一開始的指令 docker images busybox
再次確認是否有下載成功。
如果想確認這個 image 是否可以下載,可以上 DockerHub 上找,或使用 docker search
指令查詢:
$ docker search busybox
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
busybox Busybox base image. 1986 [OK]
...
這裡有個欄位 OFFICIAL
標示 OK,代表這個 image 是官方出品有掛保證的,通常會建議使用官方的 image,相較穩定可靠。
若已下載的 image 已用不到,如 hello-world
,可以使用 docker rmi
移除:
$ docker rmi hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:7f0a9f93b4aa3022c3a4c147a449bf11e0941a1fd0bf4a8e6c9408b2600777c5
Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
Deleted: sha256:9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63
docker rmi
有可能會因為 container 未移除導致 image 移除失敗,先把對應的 container 移除,再執行 docker rmi
即可:
$ docker rmi hello-world
Error response from daemon: conflict: unable to remove repository reference "hello-world" (must force) - container 7aa21315f7ca is using its referenced image bf756fb1ae65
$ docker rm 7aa21315f7ca
7aa21315f7ca
$ docker rmi hello-world
image 間如果有依賴關係,也有可能會無法正常移除,此情境未來會說明。
到這裡為止,image 已準備完成。
Docker 提供建立 container 的指令為 docker create
,實際執行範例如下:
# 建立 container
docker create -i -t --name foo busybox
# 使用 docker ps 確認 container 狀態
docker ps -a
說明 docker create
指令的選項與參數:
-i -t
簡單來說,當需要跟 container 的 process 互動時,通常會加入這兩個參數。互動指的是像 git add -i
會跟使用者一問一答的行為。--name
可以幫 container 命名,這個名字會在 docker ps
列表的 NAMES
欄位出現。必須唯一,若撞名則 container 會創建失敗。busybox
。下 docker create
後會顯示一個 digest,這與 docker ps
列表裡的 CONTAINER ID
相同。另外可以注意到這次的 STATUS
不大一樣,是 Created
,它表示 container 創建完成。
執行 container 使用 docker start
指令:
# 執行 container,`foo` 是前一節創建 container 指定的名字。
docker start -i foo
# container 內執行 Linux 指令
whoami
ls
上面執行過程中,有出現兩個不一樣的命令提示字元,一個是筆者 host 客製化的提示字元,另一個則是 / #
,這已經在 container 的世界裡了。
在 container 執行 whoami
得到的結果,會是 Docker 指定的使用者。本範例並沒有特別指定,所以是 BusyBox 預設的 root。而像 ls
的示範則是看到 container 裡的檔案系統。因為這些特色,讓 container 能做到類似 VM 的效果。
執行 BusyBox 的過程中,可以使用 Ctrl + P
與 Ctrl + Q
的連續組合鍵來達成「離開 container」--detach 的效果。離開後可以使用 docker ps
回來觀察 container 的狀態。container 還是 Up
的時候,可以使用 docker attach
再讓 container 回到前景:
# 使用 docker ps 可以觀察到狀態是 `Up`,正常運行中。
docker ps
# 將 container 裡輸入輸出綁回前景
docker attach foo
停止 BusyBox container 有兩種方法,一種是在 container 裡下結束的指令 exit
;另一種則是使用 docker stop
指令:
docker stop foo
注意這兩種方法有一點點差異,主要在於 Exited
後面的狀態碼不同,第一個方法是 0,代表正常結束。它使用正常流程 exit
指令結束 shell。
第二個方法使用 docker stop
會發送 SIGTERM
信號給 container 的主程序,等同於呼叫對主程序下 kill -15
指令一樣,是要求 process 強制結束。但因 process 結束遇到問題,因此才會出現不正常結束的狀態碼。
最後,使用 docker rm
指令移除 container,一切就會恢復成一開始還沒建 container 的狀態:
docker rm foo
以上詳細說明了 image 下載與移除的過程,以及 container 的生命週期。現在再看一次示意圖,應該會對整個流程更有感覺:
建議讀者可以多了解今天的內容,因為不管是什麼 image,都會執行今天說明的流程。唯有熟悉整個流程,才有辦法在發生問題的時候,知道是哪個環節出問題與解決對應的問題。
docker images
查看本地目前有哪些 image,用法如下:
docker images [REPOSITORY[:TAG]]
REPOSITORY
沒給的話,會列出本機所有的 image;如果有給的話,則會把該 repository 所有 tag 都列出來;如果加給 TAG
,則只會列出該 repository + tag 對應的 image。
今天的範例是只有給
REPOSITORY
。TAG
的用法類似版號,實際範例未來會有機會看到。
docker pull
從遠端 repository 下載 image,用法如下:
docker pull NAME[:TAG|@DIGEST]
TAG
若沒有給的話,預設會使用 latest,因此下面這兩個指令是等價的:
docker pull busybox
docker pull busybox:latest
docker rmi
rmi
即 rm image 之意,移除 image,用法如下:
docker rmi [OPTIONS] IMAGE [IMAGE...]
docker create
建立 container。這個指令類似 docker run
,但它只有建立 container 而沒有執行。兩個指令單純只差在有沒有執行,所以它們的參數幾乎都共用。
用法如下:
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
--name
可指定 container 名稱-i|--interactive
是讓 container 的標準輸入保持打開-t|--tty
選項是告訴 Docker 要分配一個虛擬終端機(pseudo-tty)並綁定到 container 的標準輸入上docker start
啟動 container。
docker start [OPTIONS] CONTAINER [CONTAINER...]
-i|--interactive
把標準輸入綁定到容器上。注意:這裡的
--interactive
參數與docker create
的--interactive
參數的意義不同,必須要兩個都有啟用才能與容器互動。而docker run
的--interactive
會同時兩個都啟用。
docker attach
把前景「接」到 container 上,用法如下:
docker attach [OPTIONS] CONTAINER
只要處於 detach 的 container,都能使用這個指令回到 container 上。
docker stop
強制停止指定的 container,用法:
docker stop [OPTIONS] CONTAINER [CONTAINER...]
此指令會送出 SIGTERM
信號給 container 的主程序,當 timeout(預設 10,可使用 -t|--time
參數調整)後會再送出 SIGKILL
,也就是 kill -9
。
類似地,
docker pause
是送SIGSTOP
;docker kill
則是直接送SIGKILL
。
Hello Docker 是使用 docker run
執行範例程式,今天則是了解如何操作各別指令執行 container。簡單來說,docker run
與其他指令的關係如下:
docker run = docker pull + docker create + docker start
另外也使用 --interactive
選項與 --tty
選項,成功進入 container 的環境,並在裡面執行指令(whoami
與 ls
)。
docker run
背後對應的細節docker pull
下載 imagedocker create
建立 containerdocker start
啟動 containerdocker stop
停止 container